import io
import socket
import struct
import sys
import threading
import time
# import picamera
# import ultrasonic
import regutil
import util
from multiprocessing import Queue
import AhoEdgeRegisterService_pb2 as ae
import AhoEdgeRegisterService_pb2_grpc as aeg
import grpc


print("解析DNS reg.sdju.ahhhh.com.cn ")
address = regutil.get_reg_address()
print(f"解析结果： {address}")
register_server = (address, 50051)
local_address = util.get_local_address()
print(f"获取的本地地址是：{local_address}")

# soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# while True:
#     try:
#         soc.connect(('localhost',4040))
#         soc.send(b'ACT:QUERY')
#         data = soc.recv(1024)
#         remote_host = data.decode()
#         print('get SP addr from localhost')
#         soc.close()
#         break
#     except:
#         print('Error one more time')
#         try:
#             time.sleep(1)
#         except:
#             exit(0)
#     finally:
#         pass

class AhoEdgeClient(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.in_que = Queue(1)
        self.out_que = Queue(1)
        print(f"connecting to register server: {register_server}")
        self.channel = grpc.insecure_channel(f"{register_server[0]}:{register_server[1]}")
        

    
    def get_pip(self):
        return (self.in_que, self.out_que)

    def run(self) -> None:
        self.stub = aeg.RegisterServiceStub(self.channel)
        while True:
            try:
                respone = self.stub.registerUser(ae.UserInfo(id=1, ipAddress=local_address, port=1010))
                print(f"success connected to {register_server}")
                break
            except grpc.RpcError as _:
                time.sleep(2.0)
        self.user_id = respone.user_id
        print(f"user_id = {self.user_id}")
        print("standby...")
        while True:
            cmd = self.in_que.get()
            if cmd == 0x0:
                print("got command. gRPC:getService calling")
                try:
                    response = self.stub.getService(ae.QueryRequest(serviceName="avoid"))
                except Exception as e:
                    print("error in gRPC")
                    return
                print("got gRPC response. write to out_que")
                self.out_que.put((response.ipAddress, response.port, response.id))
            elif cmd < 0xA:
                print(f"report connected to {cmd} service")
                self.stub.reportConnected(ae.ConnectedMessage(user_id=self.user_id, service_id=int(cmd)))
            elif cmd == 0xA:
                print("revc quit signal")
                self.stub.unregisterUser(ae.UserInfo(id=self.user_id))
                self.channel.close()
                return
            elif cmd > 0xE:
                server_id = cmd - 0xE
                print("reportServiceStatus")
                self.stub.reportServiceStatus(ae.ServiceStatusInfo(status=ae.ServiceStatusInfo.Status.ERROR,named="avoid", serverId=server_id))



        


# if len(sys.argv) == 2:
#     remote_host = sys.argv[1]
# elif len(sys.argv) == 3:
#     remote_host = sys.argv[1]
#     remote_port = int(sys.argv[2])


# class TransThread(threading.Thread):
#     frame = 0
#     server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

#     def __init__(self, client_pip):
#         threading.Thread.__init__(self)
#         self.send_que, self.recv_que = client_pip

#     def run(self) -> None:
#         #connection = client_socket.makefile('wb')
#         print("send command to AhoEedgClient Thread to get server info")
#         self.send_que.put(0x1)
#         (ip, port , self.server_id) = self.recv_que.get()
#         print(f"success got server info {(ip, port , self.server_id)}")

#         try:
#             print(f"try to connect {(ip, port , self.server_id)}")
#             self.server_socket.connect((ip, port))
#         except Exception as e:
#             print(f"Error: {(ip, port)}")
#         print(f"success connected to server {(ip, port)}")
#         camera = picamera.PiCamera()
#         camera.resolution = (640, 480)
#         camera.start_preview()
#         time.sleep(2)
#         stream = io.BytesIO()
#         while True:
#             try:
#                 for foo in camera.capture_continuous(stream, 'jpeg', burst=True):
#                     # time_stamp_dict[self.frame] = time.perf_counter()
#                     self.server_socket.send(struct.pack('<iiiiii', self.frame, stream.tell() + 24, 0, stream.tell(), int(ultrasonic.Distance()),int(time.time())))
#                     self.frame += 1
#                     #print(f"size of data: {(stream.tell() + 24)/1024} kb")
#                     # client_socket.flush()
#                     stream.seek(0)
#                     btytes = stream.read()
#                     self.server_socket.send(btytes)
#                     stream.seek(0)
#                     stream.truncate()
#                     echo_ = self.server_socket.recv(8)
#                     end_time = time.perf_counter()
#                     pack_id, time_stamp = struct.unpack("<ii", echo_)
#                     #print(f'time cost({pack_id}):  {end_time - time_stamp_dict[pack_id]:.3f}')
#                 self.server_socket.send(struct.pack('<L', 0))
#             except Exception as e:
#                 self.server_socket.close()
#                 self.send_que.put(0xE+self.server_id)
#                 print("reported error")

#                 print("try to find other server")
#                 print("send command to AhoEdgeThread")
#                 self.send_que.put(0x1)
#                 server_info = self.recv_que.get()
#                 print(f"success got server info {server_info}")
#                 (ip, port , self.server_id) = server_info
#                 if ip == "0.0.0.0":
#                     self.send_que.put(0xA)
#                     return
#                 try:
#                     self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#                     self.server_socket.connect((ip, port))
#                 except Exception as e:
#                     print("error with in error:" + e)
#                     self.send_que.put(0xA)
#                     return


aho_edge_client_thread = AhoEdgeClient()
# trans_thread = TransThread(aho_edge_client_thread.get_pip())

(send, recv) = aho_edge_client_thread.get_pip()
aho_edge_client_thread.start()
# trans_thread.start()
# trans_thread.join()
try:
    while (cmd := input(">")):
        if cmd == 'query':
            send.put(0x0)
            (ip, port, service_id) = recv.get()
            if ip != '0.0.0.0':
                print(f"got server {ip}:{port}")
                ack = input("Confire to connect\n>")
                if ack == 'ok':
                    send.put(service_id)
                else:
                    print("fine.")
            else:
                print("Not more server now")
        elif cmd == 'q':
            send.put(0xA)
            break
        elif cmd == 're':
            server_id = input("type the error service id:\n>")
            send.put(0xE+int(server_id))
except Exception as _:
    send.put(0xA)